home *** CD-ROM | disk | FTP | other *** search
- //--------------------------------------------------------------------------
- //
- // XMS.CPP: body of XMS interface library.
- // Copyright (c) J.English 1993.
- // Author's address: je@unix.brighton.ac.uk
- //
- // Permission is granted to use copy and distribute the
- // information contained in this file provided that this
- // copyright notice is retained intact and that any software
- // or other document incorporating this file or parts thereof
- // makes the source code for the library of which this file
- // is a part freely available.
- //
- // MODIFIED BY MAXTAL PTY LTD
- //--------------------------------------------------------------------------
- //
- // Revision history:
- // 2.0 Nov 1993 Initial coding
- // 2.1 Aug 1994 Modified to handle odd no of bytes
- // Added routine to get # of available handles
- //
- // COMMENT: Note the "clever" way the block byte move functions
- // call the one byte move functions if they have to move an odd number of
- // bytes, which in turn call the block move functions again!
- //--------------------------------------------------------------------------
-
- #include "xms.h"
- #include <dos.h>
- #include <mem.h>
- #include <stdlib.h>
-
- //--------------------------------------------------------------------------
- //
- // Data structure declarations.
- //
- struct XMSmove // descriptor for XMS moves
- {
- long count; // ... number of bytes to move
- int srchandle; // ... source handle (0 for real memory)
- long srcoffset; // ... source offset (or far pointer)
- int dsthandle; // ... destination handle (0 for real memory)
- long dstoffset; // ... destination offset (or far pointer)
- };
-
-
- //--------------------------------------------------------------------------
- //
- // Constants.
- //
- const long K = 1024; // size of a kilobyte in bytes
- const int PARA = 16; // size of a paragraph in bytes
-
-
- //--------------------------------------------------------------------------
- //
- // Globals (statics).
- //
- static void far (*XMSdriver)() = 0; // pointer to XMS driver routine
- static int XMSinited = 0; // has XMSinit been called already?
- static XMSmove descriptor; // why use more than one?
- static int A20enabled; // original A20 state
-
- //--------------------------------------------------------------------------
- //
- // XMSinit: initialise XMS system (first time only).
- //
- // The first time it is called, this function locates the XMS driver
- // and allocates a handle for a zero-byte block. It returns TRUE if
- // a handle was successfully allocated. Subsequent calls return the
- // same value.
- //
- static XMS::error XMSinit ()
- {
- //--- check if this is the first time XMSinit has been called
- if (XMSinited == 0)
- {
- //--- now it isn't!
- XMSinited = 1;
-
- //--- check if an XMS driver is present (magic spell)
- REGS r;
- r.x.ax = 0x4300;
- int86 (0x2F, &r, &r);
- if (r.h.al != 0x80)
- return XMS::NO_DRIVER;
-
- //--- get the XMS driver's address (magic spell)
- SREGS s;
- r.x.ax = 0x4310;
- int86x (0x2F, &r, &r, &s);
- XMSdriver = (void far (*)()) MK_FP(s.es,r.x.bx);
- }
-
- //--- return success indicator
- return (XMSdriver != 0 ? XMS::SUCCESS : XMS::NO_DRIVER);
- }
-
-
- //--------------------------------------------------------------------------
- //
- // XMScopy: copy block to/from XMS.
- //
- // This function copies data in accordance with the parameters set
- // up in the structure "descriptor". Overlapping blocks may not be
- // handled correctly (as per XMS specification). It does nothing if
- // XMS initialisation fails.
- //
- static XMS::error XMScopy ()
- {
- XMS::error result = XMSinit ();
- if (result == XMS::SUCCESS)
- { _SI = FP_OFF (&descriptor);
- _AH = 0x0B;
- XMSdriver ();
- if (_AX == 0)
- result = XMS::error (_BL);
- }
- return result;
- }
-
- //--------------------------------------------------------------------------
- //
- // XMS::XMS.
- //
- // Constructor for class XMS. Initialises XMSdriver if necessary,
- // and attempts to allocate a block of the specified number of bytes
- // (which will be rounded up to the nearest K).
- //
- XMS::XMS (long size)
- {
- handle = 0;
- allocation = 0;
- if ((status = XMSinit()) == SUCCESS)
- { int result = 0;
- int realsize;
- size += K - 1;
- int request = size / K;
- _DX = request;
- _AH = 0x09;
- XMSdriver ();
- result = _AX;
- if (result)
- { handle = _DX;
- _AH = 0x0E;
- XMSdriver ();
- result = _AX;
- realsize = _DX;
- }
- else
- status = error (_BL);
- if (result)
- allocation = realsize * K;
- }
- }
-
-
- //--------------------------------------------------------------------------
- //
- // XMS::~XMS: release the XMS handle (if any).
- //
- XMS::~XMS ()
- {
- if (handle)
- { _DX = handle;
- _AH = 0x0A;
- XMSdriver ();
- }
- }
-
- //--------------------------------------------------------------------------
- //
- // XMS::resize.
- //
- // Resize existing XMS allocation.
- //
- XMS::error XMS::resize (long newsize)
- {
- error result = (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
- int size;
- if (handle)
- { result = SUCCESS;
- newsize += K - 1;
- int request = newsize / K;
- _DX = handle;
- _BX = request;
- _AH = 0x0F;
- XMSdriver ();
- if (_AX != 0)
- { _DX = handle;
- _AH = 0x0E;
- XMSdriver ();
- size = _DX;
- }
- if (_AX != 0)
- allocation = size * K;
- else
- result = error (_BL);
- }
- return result;
- }
-
-
- //MAXTAL: NEW ONE BYTE MOVE----------------------------------------------
- // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
- unsigned char XMS :: get (const XMS :: XMSptr & x)
- {
- unsigned char buffer [2];
- XMS :: copy (buffer, x, 2);
- return buffer [0];
- }
-
- //MAXTAL: NEW ONE BYTE MOVE----------------------------------------------
- // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
- void XMS :: put (const XMS :: XMSptr & x, unsigned char ch)
- {
- unsigned char buffer [2];
- XMS :: copy (buffer, x, 2);
- // get
- buffer [0] = ch;
- XMS :: copy (x, buffer, 2);
- // put
- }
-
- //MAXTAL: MODIFIED----------------------------------------------------------
- //
- // XMS::at.
- //
- // Returns a descriptor identifying a particular byte offset in a
- // particular XMS object for use in the "copy" operations below.
- //
- XMS::XMSptr XMS::at (long offset)
- {
- XMSptr p(handle, offset); //MAXTAL
- return p;
- }
-
- //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
- // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
- //
- // XMS::copy.
- //
- // Copy from XMS to XMS.
- //
- XMS::error XMS::copy (const XMS::XMSptr& to,
- const XMS::XMSptr& from,
- unsigned len)
- {
- if (from.handle == 0 || to.handle == 0)
- return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
-
- error result = SUCCESS;
- unsigned long evens = len & ~1UL;
- int odds = len & 1;
- if (evens != 0)
- {
- descriptor.count = evens;
- descriptor.srchandle = from.handle;
- descriptor.srcoffset = from.offset;
- descriptor.dsthandle = to.handle;
- descriptor.dstoffset = to.offset;
- result = XMScopy();
- }
- if (odds)
- put (to [len - 1], get (from [len - 1] ) );
- return result;
- }
-
-
- //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
- // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
- //
- // XMS::copy.
- //
- // Copy from XMS to conventional memory.
- //
- XMS::error XMS::copy (void far* to,
- const XMS::XMSptr& from,
- unsigned len)
- {
- if (from.handle == 0)
- return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
- error result=SUCCESS;
- unsigned long evens = len & ~1UL;
- int odds = len & 1;
- if (evens != 0)
- {
- descriptor.count = evens;
- descriptor.srchandle = from.handle;
- descriptor.srcoffset = from.offset;
- descriptor.dsthandle = 0;
- descriptor.dstoffset = long (to);
- result = XMScopy ();
- }
- if (odds)
- * ( (char huge * ) to + len - 1) = get (from [len - 1] );
- return result;
- }
-
-
- //MAXTAL: MODIFIED TO HANDLE ODD NO OF BYTES--------------------------------
- // WARNING: ERRORS ON THE ODD BYTE MOVE NOT DETECTED
- //
- // XMS::copy.
- //
- // Copy from conventional memory to XMS.
- //
- XMS::error XMS::copy (const XMS::XMSptr& to,
- void far* from,
- unsigned len)
- {
- if (to.handle == 0)
- return (XMSdriver == 0 ? NO_DRIVER : INVALID_OBJECT);
- error result = SUCCESS;
- unsigned long evens = len & ~1UL;
- int odds = len & 1;
- if (evens != 0)
- {
- descriptor.count = evens;
- descriptor.srchandle = 0;
- descriptor.srcoffset = (unsigned long) (from);
- descriptor.dsthandle = to.handle;
- descriptor.dstoffset = to.offset;
- result = XMScopy ();
- }
- if (odds)
- put (to[len-1], * ( (char huge * ) from + len - 1) );
- return result;
- }
-
- //--------------------------------------------------------------------------
- //
- // XMS::available.
- //
- // Returns the total size of available XMS.
- //
- long XMS::available ()
- {
- if (XMSinit () == SUCCESS)
- { _AH = 0x08;
- XMSdriver ();
- return _DX * K;
- }
- else
- return 0;
- }
-
-
- //--------------------------------------------------------------------------
- //
- // XMS::largest.
- //
- // Returns the size of the largest unallocated XMS block available.
- //
- long XMS::largest ()
- {
- if (XMSinit () == SUCCESS)
- { _AH = 0x08;
- XMSdriver ();
- return _AX * K;
- }
- else
- return 0;
- }
- //MAXTAL: NEW-------------------------------------------------------------
- //
- // XMS::havail
- //
- // Returns the number of available handles
- //
- unsigned long XMS :: havail ()
- {
- XMSinit ();
- _AH = 0x0E;
- _DX = 0;
- XMSdriver ();
- return _BL;
- }
-
-
- //--------------------------------------------------------------------------
- //
- // UMB::UMB.
- //
- // Attempt to construct a UMB block of the specified size.
- //
- UMB::UMB (long size)
- {
- address = 0;
- allocation = 0;
- if (size > (64 * K - 1) * PARA)
- status = XMS::BLOCK_TOO_BIG;
- else if ((status = XMSinit()) == XMS::SUCCESS)
- { size += PARA - 1;
- _DX = unsigned (size/PARA);
- _AH = 0x10;
- XMSdriver ();
- if (_AX != 0)
- { int bx = _BX;
- address = MK_FP (bx,0);
- allocation = unsigned (_DX);
- }
- else
- status = XMS::error (_BL);
- }
- allocation *= PARA;
- }
-
-
- //--------------------------------------------------------------------------
- //
- // UMB::~UMB.
- //
- // Destroy UMB block if it has been created successfully.
- //
- UMB::~UMB ()
- {
- if (address != 0)
- { _DX = FP_SEG (address);
- _AH = 0x11;
- XMSdriver ();
- }
- }
-
-
- //--------------------------------------------------------------------------
- //
- // UMB::largest.
- //
- // Return size of largest available UMB block.
- //
- long UMB::largest ()
- {
- long size = 0;
- if (XMSinit () == XMS::SUCCESS)
- { _AH = 0x10;
- _DX = 0xFFFF;
- XMSdriver ();
- size = unsigned (_DX);
- }
- return size * PARA;
- }
-
- //--------------------------------------------------------------------------
- //
- // HMA::HMA.
- //
- // Attempt to allocate HMA for a block of the specified size.
- //
- HMA::HMA (unsigned size)
- {
- allocation = 0;
- if (size > (64 * K) - PARA)
- status = XMS::BLOCK_TOO_BIG;
- else if ((status = XMSinit()) == XMS::SUCCESS)
- { _DX = size;
- _AH = 0x01;
- XMSdriver ();
- if (_AX != 0)
- { allocation = size;
- _AH = 0x07;
- XMSdriver ();
- A20enabled = _AX;
- if (!A20enabled)
- { _AH = 0x03;
- XMSdriver ();
- if (_AX != 0)
- return;
- }
- }
- status = XMS::error (_BL);
- }
- }
-
-
- //--------------------------------------------------------------------------
- //
- // HMA::~HMA.
- //
- // Release HMA if it has been allocated successfully.
- //
- HMA::~HMA ()
- {
- if (status == XMS::SUCCESS)
- { _AH = 0x02;
- XMSdriver ();
- if (!A20enabled)
- { _AH = 0x04;
- XMSdriver ();
- A20enabled = !_AX;
- }
- }
- }
-
-
- //--------------------------------------------------------------------------
- //
- // HMA::at.
- //
- HMA::HMAptr HMA::at (unsigned offset)
- {
- HMAptr h = { this, offset };
- return h;
- }
-
- //--------------------------------------------------------------------------
- //
- // HMA::copy.
- //
- // Copy a block from one offset in the HMA to another. The two
- // blocks should not overlap.
- //
- unsigned HMA::copy (const HMAptr& to, const HMAptr& from, unsigned len)
- {
- if (!to.hma->valid() || !from.hma->valid())
- return 0;
- if (len > to.hma->size() - to.offset)
- len = to.hma->size() - to.offset;
- if (len > from.hma->size() - from.offset)
- len = from.hma->size() - from.offset;
- _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset),
- MK_FP (0xFFFF, 0x0010 + from.offset),
- len);
- return len;
- }
-
-
- //--------------------------------------------------------------------------
- //
- // HMA::copy.
- //
- // Copy a block from the HMA to conventional memory.
- //
- unsigned HMA::copy (void far* to, const HMAptr& from, unsigned len)
- {
- if (!from.hma->valid())
- return 0;
- if (len > from.hma->size() - from.offset)
- len = from.hma->size() - from.offset;
- _fmemcpy (to, MK_FP (0xFFFF, 0x0010 + from.offset), len);
- return len;
- }
-
-
- //--------------------------------------------------------------------------
- //
- // HMA::copy.
- //
- // Copy a block from conventional memory to the HMA.
- //
- unsigned HMA::copy (const HMAptr& to, void far* from, unsigned len)
- {
- if (!to.hma->valid())
- return 0;
- if (len > to.hma->size() - to.offset)
- len = to.hma->size() - to.offset;
- _fmemcpy (MK_FP (0xFFFF, 0x0010 + to.offset), from, len);
- return len;
- }
-